<?php
class FormMaker
{
	private $arr_fields;
	private $arr_options;
	private $arr_fieldValidations;
	private $arr_fieldSets;
	
	private $o_form;
	private $arr_o_fields;
	private $arr_o_fieldSets;
	private $arr_errors;
	
	private $arr_fieldValues;
	
	/**
	 * 
	 * constructor for the FormMaker module
	 * @param array $arr_options('action'=>'action', 'method'=>'POST', 'multipart'=>false, 'form_id'=>'id', 'form_line_elem'=>'p', 'inline_errors'=> $b_inlineErrors, 'required_message'=>'required message')
	 */
	public function __construct($arr_options)
	{
		$this->arr_errors = array();
		$this->arr_fieldValues = array();
		$this->arr_options = $arr_options;
		$this->arr_fields = array();	
		$this->arr_o_fields = array();
		$this->arr_fieldValidations = array();
		$this->arr_fieldSets = array();
	}
	
	/**
	 * 
	 * Puts together the form html
	 */
	public function createForm()
	{
		$this->makeFormFieldSets();
		$this->makeFormFields();
		$this->getForm();
	}
	
	/**
	 * 
	 * Validate form inputs via the POST request
	 * encapsulates the $_POST array to a cage object via Inspekt library 
	 */
	public function validateFormInputs()
	{
		//check if a post request was made
		if(!empty($_POST) && isset($_POST)){
			//cage it using the post cage
			$arr_inputs = Inspekt::makePostCage();
			$this->validateFields($arr_inputs);
		}
	}
	
	/**
	 * 
	 * validates the form fields based on the inputted array
	 * @param Array $arr_inputs
	 */
	public function validateFields($arr_inputs)
	{
		//check if the array of field objects are empty or not
		if(!empty($this->arr_o_fields)){
			//loop through the array of objects
			//this makes sure that only registered fields are used
			foreach($this->arr_o_fields as $s_fieldId=> $o_field){
				$s_inputName = $o_field->getFieldName();
				//if the field is not set then it must be either a radiobutton or checkbox or a fake field so validate anyway
				if(isset($arr_inputs[$s_inputName])){
					$o_fieldVal = $arr_inputs[$s_inputName];
				}else{
					$o_fieldVal = '';
				}
				//get the validation rules for the field
				$arr_validationRules = $this->getFieldValidation($s_fieldId);
				$b_isValid = true;
				//validate a field per validation rule set
				foreach($arr_validationRules as $arr_validationRule){
					$b_isValid = $this->validateField($o_fieldVal, $arr_validationRule['validate']);
					if($b_isValid != true){
						//set it into the object's attributes
						$s_errorMessage = $arr_validationRule['error_message'];
						$o_field->setErrorMessage($s_errorMessage);
						$this->setFieldError($s_fieldId, $s_errorMessage);
					}
				}
				//set the value into the field
				if($b_isValid == true){
					//valid input
					if(($o_field->getFieldType() == 'radio' || $o_field->getFieldType() == 'checkbox')){
						//special case for radiobuttons and check boxes
						if($o_field->getFieldValue() == $o_fieldVal){
							$o_field->setIsDefault(true);
						}
					}else{
						//normal field as of now
						$o_field->setFieldValue($o_fieldVal);
					}
					
					$this->arr_fieldValues[$s_inputName] = $o_fieldVal;
				}
			}
		}
	}
	
	public function getFieldValues()
	{
		return $this->arr_fieldValues;
	}
	
	/**
	 * 
	 * sets the field errors into an array
	 * @param string $s_fieldId
	 * @param string $s_errorMessage
	 */
	public function setFieldError($s_fieldId, $s_errorMessage){
		$this->arr_errors[$s_fieldId][] = $s_errorMessage;
	}
	
	/**
	 * get the field errors as an array
	 * @return Array (all the errors)
	 */
	public function getFieldErrors(){
		return $this->arr_errors;
	}
	
	/**
	 * 
	 * gets the current error message just the first
	 * @param String $s_fieldId
	 * @return String(error message)
	 */
	public function getFieldError($s_fieldId){
		return reset($this->arr_errors[$s_fieldId]);
	}
	
	/**
	 * 
	 * Gets the field validation array that was configured
	 * @param String $s_fieldId
	 * @return Array validation rules
	 */
	public function getFieldValidation($s_fieldId)
	{
		return $this->arr_fieldValidations[$s_fieldId];
	}
	
	/**
	 * switch case for all validation types
	 * @param string $s_value
	 * @param array $arrFieldValidation('required'=>true, 'validateAs'=>'email')
	 */
	public function isNotEmptyRequired($s_value)
	{
		$s_value = trim($s_value);
		if($s_value == '' || empty($s_value)){
			return false;
		}else{
			return true;
		}
	}
	
	/**
	 * 
	 * validates a single field
	 * @param Object $o_fieldVal
	 * @param String $s_validateAs
	 * @return Boolean (true|false)
	 */
	public function validateField($o_fieldVal, $s_validateAs)
	{
		$b_isValid = false;
		switch($s_validateAs){
			case 'email':
				$b_isValid = Inspekt::isEmail($o_fieldVal);
				break;
				
			case 'text':
				$b_isValid = true;
				break;
			
			case 'alpha':
				$b_isValid = Inspekt::isAlpha($o_fieldVal);
				break;
				
			case 'required':
				$b_isValid = $this->isNotEmptyRequired($o_fieldVal);
				break;
		}
		return $b_isValid;
	}
	
	/**
	 * 
	 * returns the form html generated by the set fields and fieldsets
	 * @return String (HTML)
	 */
	public function getFormHtml()
	{
		$o_formHtmlObj = new FormHtml($this->o_form, $this->arr_o_fieldSets ,$this->arr_o_fields, $this->arr_options['form_line_elem']);
		return $o_formHtmlObj->getHtml();
	}
	
	/**
	 * 
	 * instantiate the form model
	 * @return Object (Instance of the Form model)
	 */
	public function getForm()
	{
		$this->o_form = new Form($this->arr_options['action'], $this->arr_options['method'], $this->arr_options['multipart'], $this->arr_options['form_id'], $this->arr_fields, $this->arr_fieldSets, $this->arr_options['form_name']);
		return $this->o_form;
	}
	
	/**
	 * 
	 * Creates the form fieldset models based on the set Fieldsets and fields
	 * 
	 */
	public function makeFormFieldSets()
	{
		if(!empty($this->arr_fieldSets)){
			foreach($this->arr_fieldSets as $s_fieldSetId=> $arr_fieldSetData){
				$this->arr_o_fieldSets[$s_fieldSetId] = new FieldSet($s_fieldSetId, $arr_fieldSetData['legend'], $arr_fieldSetData['fields'], $arr_fieldSetData['inline_errors']);
			}
		}
	}
	
	/**
	 * 
	 * Creates the instance of the Form Field Models for usage in the form and sets it to the class attributte
	 * @access private
	 */
	private function makeFormFields()
	{
		//$this->o_form = new Form($s_action, $s_method, $b_isMultiPart, $s_formIdent, $arr_fields, $arr_fieldSets);
		if(!empty($this->arr_fields)){
			//loop through the forms
			foreach($this->arr_fields as $s_fieldId=> $arr_fieldConf){
				switch($this->getFieldType($s_fieldId)){
					
					case 'text':
						$o_formField = new Input($s_fieldId, $this->getFieldName($s_fieldId), $this->getFieldLabel($s_fieldId), $this->getFieldType($s_fieldId), $this->getFieldValue($s_fieldId), $this->getFieldMaxLength($s_fieldId), $this->getIsDefault($s_fieldId));
						break;
						
					case 'radio':
						$o_formField = new Input($s_fieldId, $this->getFieldName($s_fieldId), $this->getFieldLabel($s_fieldId), $this->getFieldType($s_fieldId), $this->getFieldValue($s_fieldId), $this->getFieldMaxLength($s_fieldId), $this->getIsDefault($s_fieldId));
						break;
						
					case 'checkbox':
						$o_formField = new Input($s_fieldId, $this->getFieldName($s_fieldId), $this->getFieldLabel($s_fieldId), $this->getFieldType($s_fieldId), $this->getFieldValue($s_fieldId), $this->getFieldMaxLength($s_fieldId), $this->getIsDefault($s_fieldId));
						break;
					case 'textarea':
						$o_formField = new TextArea($s_fieldId, $this->getFieldName($s_fieldId), $this->getFieldLabel($s_fieldId), $this->getFieldType($s_fieldId), $this->getFieldValue($s_fieldId), $this->getFieldMaxLength($s_fieldId));
						break;
						
					case 'submit':
						$o_formField = new Input($s_fieldId, $this->getFieldName($s_fieldId), $this->getFieldLabel($s_fieldId), $this->getFieldType($s_fieldId), $this->getFieldValue($s_fieldId), $this->getFieldMaxLength($s_fieldId), $this->getIsDefault($s_fieldId));
						break;
						
					default:
						$o_formField = new Input($s_fieldId, $this->getFieldName($s_fieldId), $this->getFieldLabel($s_fieldId), $this->getFieldType($s_fieldId), $this->getFieldValue($s_fieldId), $this->getFieldMaxLength($s_fieldId), $this->getIsDefault($s_fieldId));
						break;
				}
				$this->arr_o_fields[$s_fieldId] = $o_formField;
			}
		}
	}
	
	/**
	 * 
	 * Retrieve the created fieldsets
	 * @return Array (Object fieldset )
	 */
	public function getFieldSets()
	{
		return $this->arr_o_fieldSets;
	}
	/**
	*
	* Retrieve the created fieldsets
	* @return Array (Object field )
	*/
	public function getFields()
	{
		return $this->arr_o_fields;
	}
	
	public function getFieldConf($s_fieldId)
	{
		return $this->arr_fields[$s_fieldId];
	}
	
	public function setFieldValue($s_fieldId, $s_value)
	{
		$o_fieldObj = $this->arr_o_fields[$s_fieldId];
		$o_fieldObj->setFieldValue($s_value);
	}
	
	/**
	 * @access public
	 * method to configure the form fieldsets
	 * @param String $s_fieldSetId
	 * @param String $s_legend
	 * @param Boolean $b_inlineErrors
	 */
	public function setFieldSet($s_fieldSetId, $s_legend, $b_inlineErrors = true)
	{
		$this->arr_fieldSets[$s_fieldSetId] = array('legend'=> $s_legend, 'fields'=> array(), 'inline_errors'=> $b_inlineErrors);
	}
	
	/**
	 * @access public
	 * set the field into the array of fields in the class instance
	 * @param string $s_fieldId
	 * @param array $arr_fieldConf('label'=>'label', 'name'=>'name', 'value'=>'value', 'minLength'=>int, 'maxLength'=>int, 'type'=>'text', 'default'=> true)
	 * @param array $arrFieldValidation(array('validate'=>'required', 'error_message'=> 'required value'))
	 * @param array $arr_selectOptions('option1'=>'value1', 'option2'=>'value2')
	 */
	public function setField($s_fieldId, $s_fieldSetId, $arr_fieldConf, $arr_fieldValidation, $arr_selectOptions = null)
	{
		if(isset($this->arr_fieldSets[$s_fieldSetId])){
			//set a field to belong in a fieldSet
			array_push($this->arr_fieldSets[$s_fieldSetId]['fields'], $s_fieldId);
		}
		$this->arr_fields[$s_fieldId] = $arr_fieldConf;
		$this->arr_fieldValidations[$s_fieldId] = $arr_fieldValidation;
	}
	
	public function getIsDefault($s_fieldId)
	{
		return $this->arr_fields[$s_fieldId]['default'];
	}
	
	public function getFieldName($s_fieldId)
	{
		return $this->arr_fields[$s_fieldId]['name'];
	}
	
	public function getFieldLabel($s_fieldId)
	{
		return $this->arr_fields[$s_fieldId]['label'];
	}
	
	public function getFieldType($s_fieldId)
	{
		return  $this->arr_fields[$s_fieldId]['type'];
	}
	
	public function getFieldMaxLength($s_fieldId)
	{
		return (int)$this->arr_fields[$s_fieldId]['maxLength'];
	}
	
	public function getFieldMinLength($s_fieldId)
	{
		return (int)$this->arr_fields[$s_fieldId]['minLength'];
	}
	
	public function getFieldValue($s_fieldId)
	{
		return $this->arr_fields[$s_fieldId]['value'];
	}
	
}